/*
 * User.cpp
 *
 *  Created on: 2014. 3. 21.
 *      Author: zenoniaonline
 */


#include "../engine.h"
#include "../system/config.h"
#include "../User.h"
#include "../constant.h"
#include "../helper.h"
#include "../command/dungeon/dungeon.h"

#include "../NLogic/QuestInfo.h"
#include "../NLogic/Bag.h"
#include "../NLogic/Equip.h"
#include "../NLogic/Trade.h"
#include "../NLogic/Item.h"
#include "../NLogic/Battle.h"
#include "../NLogic/Buff.h"
#include "../NLogic/Status.h"
#include "../NLogic/Card.h"
#include "../NLogic/SocialInfo.h"
#include "../NLogic/BattleAfterEffect.h"
#include "../NLogic/VirtualCurrency.h"
#include "../NLogic/Score.h"
#include "../NLogic/Reward.h"
#include "../NLogic/BattleResult.h"
#include "../NLogic/UserLocation.h"
#include "../NLogic/BackEndServerInfo.h"
#include "../NLogic/Fishing.h"
#include "../NLogic/Stamina.h"
#include "../NLogic/DailyMission.h"
#include "../NLogic/BattleAbility.h"

#include "../NLogic/Static.h"
#include "../NLogic/Function.h"

#include "../NLogic/NAsync/AsyncTrade.h"

#include "../NGameLog/Static.h"

#include "../NResource/Static.h"
#include "../NState/Static.h"

#include "../NProcess/Static.h"

#include "../Session.h"

#include <sstream>
#include <algorithm>    // std::for_each

#include "../Proxy.h"

#include "../Encryption.h"
#include "../Config.h"

#include "../GameLog.h"

#include <ctime>

namespace ProjectZ {

User::User() : _clsBagVector(static_cast<int>(BAG_TYPE_MAX))
, _session(NULL), _bClose(false), _bDelUser(false), _bZENEvent(false), _bBattleReconnect(false), _space(NULL), _world(NULL), _reserveSpace(NULL)
, _battle_aftereffect(false), _latency(0), _refCount(0)
{
	this->SetState(NState::Static::Instance().TITLE());

	for(int i = static_cast<int>(BAG_TYPE_NORMAL); i < static_cast<int>(BAG_TYPE_MAX); ++i)
	{
		_clsBagVector[i] = new NLogic::Bag(this, i);
	}

	_equip				= new NLogic::Equip(this);
	_battle				= new NLogic::Battle();
	_mailBox			= new NLogic::MailBox();
	_trade				= new NLogic::Trade(this);
	_buff				= new NLogic::Buff(this);
	_status				= new NLogic::Status(this);
	_card				= new NLogic::Card();
	_socialInfo			= new NLogic::SocialInfo();
	_battleAfterEffect	= new NLogic::BattleAfterEffect();
	_virtualCurrency	= new NLogic::VirtualCurrency(this);
	_score				= new NLogic::Score(this);
	_reward				= new NLogic::Reward(this);
	_battleResult		= new NLogic::BattleResult;
	_userLocation		= new NLogic::UserLocation(this);
	_memKey				= new NLogic::MemcachedKey;
	_backEndServerInfo	= new NLogic::BackEndServerInfo();
	_questInfo			= new NLogic::QuestInfo(this);
	_fishing			= new NLogic::Fishing(this);
	_stamina			= new NLogic::Stamina(this);
	_dailyMission		= new NLogic::DailyMission(this);
	_battleAbility		= new NLogic::BattleAbility(this);
	_asyncTrade			= new NLogic::NAsync::AsyncTrade();

	_dailyEPTime.reserve(8);
	for (int i = 0; i < 8; i++)
	{
		_dailyEPTime[i] = 0;
	}

	_enumStateType	= EnumState::__NONE__;

	_login = false;

	_battleRoyalBattle = NULL;
	_characterInfoSetTime = 0;
	_company = 0;
	_encrypt_key = 0;
	_loadCharacterCount = 0;
	_locationRegist = false;
	_openCharacterCount = 0;
	_loginTime = 0;
	_party = NULL;
	_sale_code = 0;
	_state = NULL;
	_userSeq = 0;
	_version = 0;
	GID = 0;
	_characterInfoCache = false;
	_userInfoCache = false;

	_isKick = false;
	_clsStateHistory.clear();
	_clsEnumStateHistory.clear();

	_clsDungeonClearInfo.Initialize(0);
	_clsDungeonClearPoint.Initialize(-1);
	_clsBagOrder.Initialize(0);

	_loadBagTypeSeq = 0;
	_partyAccept = false;
	_bagInfoCache = false;
	_bDisconnect = false;
	_worldIndex = -1;

	_serial = 1;
	
	_lastDeadTime = 0;

	_guildGrade = 0;
	_guildName.clear();

	vehicle_state = 0;
}

User::~User()
{
	delete _questInfo;
	delete _backEndServerInfo;
	delete _virtualCurrency;
	delete _battleAfterEffect;
	delete _status;
	delete _buff;
	delete _battle;
	delete _equip;
	delete _mailBox;
	delete _trade;
	delete _card;
	delete _socialInfo;
	delete _score;
	delete _reward;
	delete _battleResult;
	delete _userLocation;
	delete _memKey;
	delete _fishing;
	delete _stamina;
	delete _dailyMission;
	delete _battleAbility;
	delete _asyncTrade;

	std::for_each(_clsBagVector.begin(), _clsBagVector.end(), [](NLogic::Bag * pBag) {
		delete pBag;
	} );
}

void User::Initialize()
{
	//login = false;
	_latency = 0;

	this->_socialID.clear();
	this->_userInfo.nickname.clear();
	this->_userInfo.profile_url.clear();

	_userSeq = 0;
	_encrypt_key = 0;
	_userInfoCache = false;
	_characterInfoCache = false;
	_locationRegist = false;
	_bagInfoCache = false;
	_bDisconnect = false;
	_openCharacterCount = 0;
	_loadCharacterCount = 0;

	std::for_each(_clsBagVector.begin(), _clsBagVector.end(), [](NLogic::Bag * pBag) {
		if ( NULL != pBag )
			pBag->Initialize();
	} );

	_equip->Initialize();
	_battle->Initialize();
	_battle->SetUser(this);
	_mailBox->Initialize();
	_trade->Initialize();
	_buff->Initialize();
	_status->Initialize();
	_card->Initialize();
	_socialInfo->Initialize();
	_battleAfterEffect->Initialize();
	_virtualCurrency->Initialize();
	_score->Initialize();
	_battleResult->Initialize();
	_userLocation->Initialize();
	_memKey->Initailize();
	_backEndServerInfo->Initialize();
	_questInfo->Initialize();
	_fishing->Initialize();
	_stamina->Initialize();
	_dailyMission->Initialize();
	_asyncTrade->Initialize();
	_battleAbility->Initialize();

	_session = NULL;

	_bClose = false;
	_bDelUser = false;
	_bZENEvent = false;
	_bBattleReconnect = false;
	_space = NULL;
	_world = NULL;
	_reserveSpace = NULL;
	_worldIndex = -1;

	_enumStateType = EnumState::__NONE__;
	_party = NULL;
	_partyAccept = false;
	_battle_aftereffect = false;

	_characterInfoSetTime = 0;

	_clsDungeonClearInfo.Initialize(0);
	_clsDungeonClearPoint.Initialize(-1);
	_clsBagOrder.Initialize(0);

	_dailyEPTime.clear();
	_dailyEPTime.resize(8);

	_login = false;

	this->SetState(NState::Static::Instance().TITLE());
	_refCount = 1;

	_isKick = false;

	_company = 0;
	_sale_code = 0;

	//this->IncreaseRefCount();

	_clsStateHistory.clear();
	_clsEnumStateHistory.clear();

	_loadBagTypeSeq = 0;

	_serial = 1;
	
	_lastDeadTime = 0;

	_guildGrade = 0;
	_guildName.clear();

	vehicle_state = 0;
}

void User::Finalize()
{
	_questInfo->Finalize();
	_battle->Finalize();
	_equip->Finalize();
	_mailBox->Finalize();
	_trade->Finalize();
	_buff->Finalize();
	_status->Finalize();
	_card->Finalize();
	_socialInfo->Finalize();
	_battleAfterEffect->Finalize();
	_virtualCurrency->Finalize();
	_score->Finalize();
	_battleResult->Finalize();
	_fishing->Finalize();
	_stamina->Finalize();
	_dailyMission->Finalize();
	_asyncTrade->Finalize();
	_battleAbility->Finalize();

	std::for_each(_clsBagVector.begin(), _clsBagVector.end(), [](NLogic::Bag * pBag) {
		pBag->Finalize();
	} );

	::Dispatcher::GETTIMER()->KillTimer(this);


	_bagInfoCache = false;

	_isKick = false;
}

void User::Send(::Network::Packet *pPacket, bool printhex)
{
	if (NULL == _session)
	{
		DEBUGLOG("%s : NULL == _session", __FUNCTION__);
		::Network::GETPACKETPOOL()->SEND_DEL(pPacket);
		return;
	}

	unsigned short command = 0;

	command = pPacket->GetCommand_SendPacket();

	{
		char cmd[80];
		STRESSLOG("[SENDCOMMAND: 0x%x %s size : %d GID : %d]", command, GetCommandName(cmd, command), pPacket->GetLen(), this->GetUserSeq());
	}

	_session->SendPacket(pPacket, printhex);
}

void User::SendOneshotEncrypt(::Network::Packet *pPacket, bool printhex)
{
	if (NULL == _session)
	{
		DEBUGLOG("SESSION IS NULL GID : %d", this->GetUserSeq());
		return;
	}

	// FIXME!!!!!
	unsigned short command = 0;
	command = pPacket->GetCommand_SendPacket();

	{
		char cmd[80];
		STRESSLOG("[SENDCOMMAND: 0x%x %s size : %d GID : %d]", command, GetCommandName(cmd, command), pPacket->GetLen(), this->GetUserSeq());
	}

	_session->SendPacketAsync(pPacket);
}

void
User::SetLogin()
{
	_login = true;
	_userLocation->SetUserLocation(0);
}

void User::SetCoordinate(int x, int y, int degree)
{
	_battle->GetData().x = x;
	_battle->GetData().y = y;
	_battle->GetData().degree = degree;
}

void User::Set_PK_Coordinate(int x, int y, int degree)
{
	SetCoordinate(x,y,degree);

	if (NULL == _battleRoyalBattle)
		return;

	_battleRoyalBattle->GetData().x = x;
	_battleRoyalBattle->GetData().y = y;
	_battleRoyalBattle->GetData().degree = degree;

	DEBUGLOG("GetBattleRoyalBattle %s x : %d y : %d GID : %d", __FUNCTION__, x, y, this->GetUserSeq());
}

void
User::SetUserSeq(int userSeq)
{
	_userSeq = userSeq;
	_memKey->SetMemcachedKey(userSeq);
}

void
User::SetUserInfo(UserInfo & userInfo)
{
	_userInfo = userInfo;
	_userInfoCache = true;

	_userInfo.nickname = this->GetUserNickName();
	_userInfo.uuid = this->Getuuid();

	_userInfo.company = this->GetCompany();
	_userInfo.sale_code = this->GetSaleCode();
}

void
User::SetCharacterInfo(CharacterInfo & characterInfo, int slotIndex)
{
	if (slotIndex < 0 || slotIndex > 7)
	{
		DEBUGLOG("ERROR : %s slotIndex : %d GID : %d", slotIndex, this->GetUserSeq());
		return;
	}


	_characterInfo[slotIndex] = characterInfo;

	if (_userInfo.main_slot_index == -1)
	{
		_userInfo.main_slot_index = slotIndex;
	}

	if (_userInfo.main_slot_index == slotIndex)
	{
		//DEBUGLOG("TRACE main slot load dungeon slotIndex : %d GID : %d", slotIndex, this->GetUserSeq());
		this->load_DungeonClear_BagOrder_Buff_BattleAfterEffect();
		this->load_Daily_Mission_Info();
	}


}

void
User::SetLocationRegist()
{
	_locationRegist = true;
}

void
User::SetCharacterInfoSetTime(time_t characterInfoSetTime)
{
	_characterInfoSetTime = characterInfoSetTime;
}

time_t
User::GetCharacterInfoSetTime()
{
	return _characterInfoSetTime;
}

void
User::SetLoginTime(time_t loginTime)
{
	_loginTime = loginTime;
}

time_t
User::GetLoginTime()
{
	return _loginTime;
}

void
User::SetAllDailyEPTime(time_t settime)
{
	std::for_each(_dailyEPTime.begin(), _dailyEPTime.end(), [&](time_t & dailyEPTime){
		dailyEPTime = settime;
	});
}

void
User::SetDailyEPTime(time_t settime)
{
	_dailyEPTime[_userInfo.main_slot_index] = settime;
}

time_t
User::GetDailyEPTime()
{
	return _dailyEPTime[_userInfo.main_slot_index];
}

void
User::FlushUserInfo()
{
	if (true == _userInfoCache && true == this->GetLogin())
	{
		this->_reward->save_Reward();
		this->_score->SaveMedal();
		::ProjectZ::NProxy::FlushUserInfoSyn(this, true);
		::ProjectZ::NProxy::FlushFRUserInfoSyn(this);
	}
}

void
User::FlushCharacterInfo()
{
	if (true == _characterInfoCache && true == this->GetLogin())
	{
		::ProjectZ::NProxy::FlushCharacterInfoSyn(this, this->GetCharacterInfo().characterseq, true);
	}
}

void
User::FlushNewCharacterInfo(int slotindex)
{
	if (true == _characterInfoCache && true == this->GetLogin())
	{
		::ProjectZ::NProxy::FlushNewCharacterInfoSyn(this, this->GetCharacterInfoFromIndex(slotindex).characterseq, slotindex, true);
	}
}

void
User::FlushUserInfoCache()
{
	if (true == _userInfoCache && true == this->GetLogin())
	{
		this->_reward->save_Reward();
		this->_score->SaveMedal();
		::ProjectZ::NProxy::FlushUserInfoSyn(this, false);
		::ProjectZ::NProxy::FlushFRUserInfoSyn(this);
	}
}

void
User::FlushCharacterInfoCache()
{
	if (true == _characterInfoCache && true == this->GetLogin())
	{
		::ProjectZ::NProxy::FlushCharacterInfoSyn(this, this->GetCharacterInfo().characterseq, false);
	}
}

void
User::UnRegistLocation()
{
	if (true == _locationRegist)
	{
		DEBUGLOG("[CHANNEL User::UnRegistUser()]");
		::ProjectZ::NProxy::UnRegistUser(this);
	}
}

NLogic::Bag *
User::GetBag(INVEN_BAG_TYPE eBagType)
{
	if (eBagType < BAG_TYPE_NORMAL || eBagType >= BAG_TYPE_MAX)
		return NULL;


	return _clsBagVector[static_cast<int>(eBagType)];
}

NLogic::Equip *
User::GetEquip()
{
	return _equip;
}


NLogic::MailBox *
User::GetMailBox()
{
	return _mailBox;
}

NLogic::Trade *
User::GetTrade()
{
	return _trade;
}

NLogic::Buff *
User::GetBuff()
{
	return _buff;
}

NLogic::Status *
User::GetStatus()
{
	return _status;
}

NLogic::Card *
User::GetCard()
{
	return _card;
}

NLogic::SocialInfo *
User::GetSocialInfo()
{
	return _socialInfo;
}

NLogic::BattleAfterEffect *
User::GetBattleAfterEffect()
{
	return _battleAfterEffect;
}

NLogic::VirtualCurrency *
User::GetVirtualCurrency()
{
	return _virtualCurrency;
}
NLogic::Score *
User::GetScore()
{
	return _score;
}

NLogic::Reward *
User::GetReward()
{
	return _reward;
}

NLogic::BattleResult *
User::GetBattleResult()
{
	return _battleResult;
}

NLogic::UserLocation *
User::GetUserLocation()
{
	return _userLocation;
}

NLogic::MemcachedKey *
User::GetMemKey()
{
	return _memKey;
}

NLogic::BackEndServerInfo *
User::GetBackEndServerInfo()
{
	return _backEndServerInfo;
}

NLogic::QuestInfo *
User::GetQuestInfo()
{
	return _questInfo;
}

NLogic::Fishing *
User::GetFishing()
{
	return _fishing;
}

NLogic::Stamina *
User::GetStamina()
{
	return _stamina;
}

NLogic::NAsync::AsyncTrade *
User::GetAsyncTrade()
{
	return _asyncTrade;
}

NLogic::DailyMission *
User::GetDailyMission()
{
	return _dailyMission;
}

NLogic::BattleAbility *
User::GetBattleAbility()
{
	return _battleAbility;
}

bool
User::GiveBaseItem(int slotIndex)
{
	// 1. 기본 무기...
	{
		NLogic::Item::Data clsData;
		clsData.tid = 0;
		clsData.sub_type = CLASS_ITEM_TABLE_WEAPONE;
		clsData.quantity = 1;
		clsData.class_type = GetCharacterInfoFromIndex(slotIndex).classtype;
		clsData.bag_type = NResource::Static::InstancePtr()->GetItemResource()->GetItemBagType(clsData);
		clsData.bag_slot_number = 0;

		NResource::Static::InstancePtr()->GetItemResource()->setItemEffect(clsData);

		// MEMO: DB 에만 아이템을 넣은 것이므로, DEL_ITEM() 호출이 필요하다
		NLogic::Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
		pItem->Open_Normal(clsData, this);
		pItem->InsertToDatabaseItemInfo(slotIndex);
		GetCharacterInfoFromIndex(slotIndex).weapon = pItem->GetItemSeq();
		GetCharacterInfoFromIndex(slotIndex).weapon_iconidx = 0;
		NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
	}

	// 2. Fairy
	{
		NLogic::Item::Data clsData;
		NResource::Static::InstancePtr()->GetFairyGachya()->SetBaseFairyInfo(this, clsData, GetCharacterInfoFromIndex(slotIndex).classtype);
		clsData.bag_slot_number = 0;

		NLogic::Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
		pItem->Open_Fairy(clsData, this);
		pItem->InsertToDatabaseItemInfo(slotIndex);
		GetCharacterInfoFromIndex(slotIndex).fairy = pItem->GetItemSeq();
		NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
	}

	// 2. vehicle
	{
		NLogic::Item::Data clsData;
		clsData.tid = 0;
		clsData.sub_type = CLASS_ITEM_TABLE_VEHICLE;
		clsData.quantity = 1;
		clsData.class_type = -1;
		clsData.bag_type = NResource::Static::InstancePtr()->GetItemResource()->GetItemBagType(clsData);
		clsData.bag_slot_number = 0;

		NResource::Static::InstancePtr()->GetItemResource()->setItemEffect(clsData);

		// MEMO: DB 에만 아이템을 넣은 것이므로, DEL_ITEM() 호출이 필요하다
		NLogic::Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
		pItem->Open_Normal(clsData, this);
		pItem->InsertToDatabaseItemInfo(slotIndex);
		GetCharacterInfoFromIndex(slotIndex).vehicle = pItem->GetItemSeq();
		GetCharacterInfoFromIndex(slotIndex).vehicle_iconidx = 0;
		NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
	}

	if (true == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(static_cast<int>(ContentsOpen::GIVE_BASE_HELMET)))
	{
		// 3. helmet
		{
			NLogic::Item::Data clsData;
			clsData.tid = 0;
			clsData.sub_type = CLASS_ITEM_TABLE_HELMET;
			clsData.quantity = 1;
			clsData.class_type = this->GetCharacterInfoFromIndex(slotIndex).classtype;
			clsData.bag_type = NResource::Static::InstancePtr()->GetItemResource()->GetItemBagType(clsData);
			clsData.bag_slot_number = 0;

			NResource::Static::InstancePtr()->GetItemResource()->setItemEffect(clsData);

			// MEMO: DB 에만 아이템을 넣은 것이므로, DEL_ITEM() 호출이 필요하다
			NLogic::Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
			pItem->Open_Normal(clsData, this);
			pItem->InsertToDatabaseItemInfo(slotIndex);
			NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
		}
	}

	if (true == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(static_cast<int>(ContentsOpen::GIVE_BASE_BATTLEPET)))
	{
		// 4. battle pet
		{
			NLogic::Item::Data clsData;
			if (true == NResource::Static::InstancePtr()->GetBattlepetGachya()->SetBaseBattlePetInfo(this, clsData, 1, 1))
			{
				// MEMO: DB 에만 아이템을 넣은 것이므로, DEL_ITEM() 호출이 필요하다
				NLogic::Item * pItem = NLogic::Static::InstancePtr()->NEW_ITEM();
				pItem->Open_Normal(clsData, this);
				pItem->InsertToDatabaseItemInfo(slotIndex);
				NLogic::Static::InstancePtr()->DEL_ITEM(pItem);
			}
		}
	}

	return true;
}

void
User::SetSpace(NLogic::Space * space)
{
	_space = space;
}

NLogic::Space *
User::GetSpace()
{
	return _space;
}

void
User::SetReserveSpace(NLogic::Space * pSpace)
{
	_reserveSpace = pSpace;
}

NLogic::Space *
User::GetReserveSpace()
{
	return _reserveSpace;
}

NLogic::Battle *
User::GetBattle()
{
	return _battle;
}

void
User::OnDisconnect()
{
	STRESSLOG("ONDISCONNECT SOCIALID : %s", this->GetSocialID().c_str());
	_userLocation->DelUserLocation();

	if(this->GetEnumState() == EnumState::RECALL
			|| this->GetEnumState() == EnumState::PHYSICAL_CHANGE
			|| this->GetState() == NState::Static::InstancePtr()->PHYSICALCHANGE())
	{
		this->CleanUp();
		return;
	}

	_session = NULL;
	this->SetState(NState::Static::Instance().WAITRECONNECT());
	//this->SetEnumState(EnumState::RECONNECT_WAIT);

	// 10 초 타이머 진행....
	::Dispatcher::Timer::Argument clsArgument(1000 * 10, static_cast<int>(TimerID::DISCONNECT), NULL, this);
	::Dispatcher::GETTIMER()->SetTimer(clsArgument);
}

void
User::OnReconnect()
{
	STRESSLOG("ONRECONNECT SOCIALID : %s", this->GetSocialID().c_str());

//	if (false == this->GetLogin())
//	{
//		this->DecreaseRefCount();
//		return;
//	}

	if (true == _isKick)
	{
		return;
	}

	::Dispatcher::GETTIMER()->KillTimer(this, static_cast<int>(TimerID::DISCONNECT));

	if (_state != NState::Static::Instance().MAINFRIENDLIST())
	{
		this->SetState(NState::Static::Instance().MAINFRIENDLIST());
	}

	//this->SetEnumState(EnumState::__NONE__);

	// PVP 전투 중에 접속이 끊어 졌다가 Reconnect되는 경우
	if (true == _bBattleReconnect)
	{
		this->IncreaseRefCount();
		_bBattleReconnect = false;
	}

	this->ResetSerial();

//	// Reconnect시에 Disconnect 변수 false로 초기화
//	if (true == _bDisconnect)
//		_bDisconnect = false;
}

void
User::CleanUp()
{
	STRESSLOG("CLEANUP SOCIALID : %s", this->GetSocialID().c_str());

	if (_state == NState::Static::Instance().CLEANUP())
	{
		::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "CRITICAL %s GID : %d REFCOUNT : %d", __FUNCTION__, this->GetUserSeq(), this->GetRefCount());
		this->RewindState();
		this->RewindEnumState();
		return;
	}

	ProjectZ::NGameLog::LogConnectionInfo(this);

	::ProjectZ::NGameLog::Bson * pBson = ::ProjectZ::NGameLog::Static::Instance().GETBSONPOOL()->NEW();
	if(NULL != pBson)
	{
		time_t curtime = time(NULL);
		pBson->SetCollections("log_game_play");
		bson * bson = pBson->GetBsonData();
		bson_append_int( bson, "user_seq", this->_userSeq );
		bson_append_int( bson, "company", this->_company );
		bson_append_int( bson, "sale_code", this->_sale_code );
		bson_append_time_t( bson, "login_time", this->_loginTime );
		bson_append_time_t( bson, "logout_time", curtime );
		bson_append_int( bson, "play_time", curtime - this->_loginTime );

		::ProjectZ::NGameLog::MongoDB * pMongoDB = ::ProjectZ::NGameLog::Static::Instance().GetMongoDB();
		pMongoDB->Push(pBson);
	}

	this->GetUserLocation()->DelUserLocation();

	if (_state == NState::Static::Instance().WAITRECONNECT())
		::Dispatcher::GETTIMER()->KillTimer(this, static_cast<int>(TimerID::DISCONNECT));

	NLogic::Space * pSpace = this->GetSpace();
	NLogic::Space * pWorldSpace = this->_getWorldSpace();

	if (pSpace != NULL ) pSpace->LeaveUser(this);
	if (pWorldSpace != NULL && pSpace != pWorldSpace) pWorldSpace->LeaveUser(this);
	if (NULL != this->GetReserveSpace()) { this->GetReserveSpace()->EraseReserveUser(this); }
	_reserveSpace = NULL;

	this->SetDelUser();
	this->DecreaseRefCount();
	this->SetState(NState::Static::Instance().CLEANUP());

	if (NULL != _session) { _session->ResetUser(); _session->Close(); }

	// PVP에 묶여 있어서 유저가 정리되지 못 한 경우, Reconnect 요청이 들어오면 Ref카운트를 증가 시켜주기 위해 Flag 세팅
	if (this->GetRefCount() >= 1 && pSpace != NULL)
	{
		if (pSpace->GetData()._spaceType == NLogic::Space::SpaceType::PVP_USER
				|| pSpace->GetData()._spaceType == NLogic::Space::SpaceType::NEW_PVP_ROOM)
		{
			_bBattleReconnect = true;
		}
	}

	if (this->GetRefCount() >= 1 && pSpace != NULL && pSpace->GetData()._spaceType == NLogic::Space::SpaceType::BATTLEROYAL)
	{
		_bBattleReconnect = true;
	}
}

void
User::ForceCleanUp()
{
	//if (NULL != _session) { _session->Close(); return; }
	STRESSLOG("CLEANUP SOCIALID : %s", this->GetSocialID().c_str());

	ProjectZ::NGameLog::LogConnectionInfo(this, 1);

	::ProjectZ::NGameLog::Bson * pBson = ::ProjectZ::NGameLog::Static::Instance().GETBSONPOOL()->NEW();
	if(NULL != pBson)
	{
		time_t curtime = time(NULL);
		pBson->SetCollections("log_game_play");
		bson * bson = pBson->GetBsonData();
		bson_append_int( bson, "user_seq", this->_userSeq );
		bson_append_int( bson, "company", this->_company );
		bson_append_int( bson, "sale_code", this->_sale_code );
		bson_append_time_t( bson, "login_time", this->_loginTime );
		bson_append_time_t( bson, "logout_time", curtime );
		bson_append_int( bson, "play_time", curtime - this->_loginTime );

		::ProjectZ::NGameLog::MongoDB * pMongoDB = ::ProjectZ::NGameLog::Static::Instance().GetMongoDB();
		pMongoDB->Push(pBson);
	}

	this->GetUserLocation()->DelUserLocation();

	if (_state == NState::Static::Instance().WAITRECONNECT())
		::Dispatcher::GETTIMER()->KillTimer(this, static_cast<int>(TimerID::DISCONNECT));

	NLogic::Space * pSpace = this->GetSpace();
	NLogic::Space * pWorldSpace = this->_getWorldSpace();

	if (pSpace != NULL ) pSpace->LeaveUser(this);
	if (pWorldSpace != NULL && pSpace != pWorldSpace) pWorldSpace->LeaveUser(this);


	if (NULL != _session)
	{
		_session->ResetUser();
		_session->Close();
	}

	if (NULL != this->GetReserveSpace()) { this->GetReserveSpace()->EraseReserveUser(this); }

	_reserveSpace = NULL;

	this->SetDelUser();
	this->DecreaseRefCount();
	this->SetState(NState::Static::Instance().CLEANUP());

	// PVP에 묶여 있어서 유저가 정리되지 못 한 경우, Reconnect 요청이 들어오면 Ref카운트를 증가 시켜주기 위해 Flag 세팅
	if (this->GetRefCount() >= 1 && pSpace != NULL)
	{
		if (pSpace->GetData()._spaceType == NLogic::Space::SpaceType::PVP_USER
				|| pSpace->GetData()._spaceType == NLogic::Space::SpaceType::NEW_PVP_ROOM)
		{
			_bBattleReconnect = true;
		}
	}

	if (this->GetRefCount() >= 1 && pSpace != NULL && pSpace->GetData()._spaceType == NLogic::Space::SpaceType::BATTLEROYAL)
	{
		_bBattleReconnect = true;
	}
}


void
User::PhysicalChangeCleanUp()
{
	STRESSLOG("PHYSICAL CHANGE CLEANUP SOCIALID : %s", this->GetSocialID().c_str());

	ProjectZ::NGameLog::LogConnectionInfo(this);

	::ProjectZ::NGameLog::Bson * pBson = ::ProjectZ::NGameLog::Static::Instance().GETBSONPOOL()->NEW();
	if(NULL != pBson)
	{
		time_t curtime = time(NULL);
		pBson->SetCollections("log_game_play");
		bson * bson = pBson->GetBsonData();
		bson_append_int( bson, "user_seq", this->_userSeq );
		bson_append_int( bson, "company", this->_company );
		bson_append_int( bson, "sale_code", this->_sale_code );
		bson_append_time_t( bson, "login_time", this->_loginTime );
		bson_append_time_t( bson, "logout_time", curtime );
		bson_append_int( bson, "play_time", curtime - this->_loginTime );

		::ProjectZ::NGameLog::MongoDB * pMongoDB = ::ProjectZ::NGameLog::Static::Instance().GetMongoDB();
		pMongoDB->Push(pBson);
	}

	this->GetUserLocation()->DelUserLocation();

	NLogic::Space * pSpace = this->GetSpace();
	NLogic::Space * pWorldSpace = this->_getWorldSpace();

	if (pSpace != NULL ) pSpace->LeaveUser(this);
	if (pWorldSpace != NULL && pSpace != pWorldSpace) pWorldSpace->LeaveUser(this);
	if (NULL != this->GetReserveSpace()) { this->GetReserveSpace()->EraseReserveUser(this); }
	_reserveSpace = NULL;

	this->DecreaseRefCount_PhysicalChange();
}




void
User::SetZENEventFlag()
{
	_bZENEvent = NResource::Static::InstancePtr()->GetEventTime()->IsZENDiscountEvent(this);
}

bool
User::GetZENEventFlag()
{
	return _bZENEvent;
}

bool
User::OnTime(int id, void* param)
{
	switch(id)
{
	case static_cast<int>(TimerID::DISCONNECT):
		{
			this->CleanUp();
		}
		break;
	}
	return false;
}

void
User::OnCPI()
{
	int reward = GetCPIReward();

	if (reward <= 0)
	{
		DEBUGLOG("OnCPI : reward <= 0!! reward=%d", reward);
		DecreaseRefCount();
		return;
	}

	if (reward > 100)
	{
		DEBUGLOG("OnCPI : reward > 100!! reward=%d", reward);
		DecreaseRefCount();
		return;
	}

	NLogic::MailBox::Mail::Data clsMailData;

	clsMailData.send_user_seq		= 0;
	clsMailData.send_user_nickname	= "GAMEVIL";
	clsMailData.recv_user_seq		= this->GetUserSeq();
//	clsMailData.gold				= reward;
//	clsMailData.gift_status			= EM_GIFT_GOLD;
	clsMailData.zen					= reward;
	clsMailData.gift_status			= EM_GIFT_ZEN;
	clsMailData.gift_vcindex		= EM_VCINDEX_CPI;
	clsMailData.message				= NResource::Static::InstancePtr()->GetMailMessageResource()->GetMessageFreeChargeReward();

	// 메일 발송
	if (false == NLogic::NFunction::SendMail(this, clsMailData))
	{
		DEBUGLOG("OnCPI : false == NLogic::NFunction::SendMail");
		DecreaseRefCount();
		return;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<int16_t>(ACK_OK);
	pAck->MakePacket(CMD_SC_CPI_REQUEST);
	this->Send(pAck);

	DecreaseRefCount();
}

void
User::OnReceiptCheck()
{
	DEBUGLOG("%s : userseq=%d, refcount=%d, pointer=%x", __FUNCTION__, this->GetUserSeq(), this->GetRefCount(), this);

	::Dispatcher::Handler::ReceiptCheckWrapper::Data & clsReceiptData = this->GetReceiptCheckData();

	if (ACK_OK != clsReceiptData._ack)
	{
//		DecreaseRefCount();
		if (this->GetEnumState() == User::EnumState::RECEIPT_CHECKING_CLOSE)
		{
			this->OnDisconnect();
			return;
		}

		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pAck << static_cast<int16_t>(clsReceiptData._ack);
		*pAck << static_cast<uint32_t>(clsReceiptData._validatorStatus);
		*pAck << this->GetVirtualCurrency()->GetZen();
		pAck->MakePacket(CMD_SC_REG_BUY_ITEM_RESULT);
		this->Send(pAck);

		this->SetEnumState(User::EnumState::__NONE__);
		this->SetState(NState::Static::Instance().MAINFRIENDLIST());

		return;
	}

	NResource::ProductData::Flyweight * pFly = NResource::Static::InstancePtr()->GetProductResource()->GetFly(this, clsReceiptData._tid);
	if (NULL == pFly)
	{
		PROCESSLOG("%s : pFly is NULL!! userseq=%d", __FUNCTION__, this->GetUserSeq());
//		DecreaseRefCount();

		if (this->GetEnumState() == User::EnumState::RECEIPT_CHECKING_CLOSE)
		{
			this->OnDisconnect();
			return;
		}

		this->SetEnumState(User::EnumState::__NONE__);
		this->SetState(NState::Static::Instance().MAINFRIENDLIST());
		return;
	}

	// 젠 선물
	if (1 == clsReceiptData._isGift)
	{
		NLogic::MailBox::Mail::Data clsMailData;
		clsMailData.send_user_seq		= this->GetUserSeq();
		clsMailData.send_user_nickname	= this->GetUserInfo().nickname.c_str();
		clsMailData.send_user_imageurl	= this->GetUserInfo().profile_url.c_str();
		clsMailData.recv_user_seq		= clsReceiptData._recvUserSeq;
		clsMailData.message				= NResource::Static::InstancePtr()->GetMailMessageResource()->GetMessageGiftZen();
		clsMailData.zen					= pFly->_DEFAULT_AMOUNT + pFly->_BONUS_AMOUNT;
		clsMailData.gift_vcindex		= pFly->_GIFT_VC_INDEX;
		clsMailData.gift_status			= EM_GIFT_ZEN;

		if (false == NLogic::NFunction::SendMail(this, clsMailData))
		{
			PROCESSLOG("%s : false == NLogic::NFunction::SendMail!! send=%d, recv=%d", __FUNCTION__, this->GetUserSeq(), clsReceiptData._recvUserSeq);
//			DecreaseRefCount();

			if (this->GetEnumState() == User::EnumState::RECEIPT_CHECKING_CLOSE)
			{
				this->OnDisconnect();
				return;
			}

			this->SetEnumState(User::EnumState::__NONE__);
			this->SetState(NState::Static::Instance().MAINFRIENDLIST());
			return;
		}
	}
	else
	{
		// VC 히스토리 저장
		DEBUGLOG("%s : userseq=%d, tid=%d, vcIndex=%d", __FUNCTION__, this->GetUserSeq(), clsReceiptData._tid, pFly->_VC_INDEX);

		NLogic::NFunction::VCProcess(this, pFly->_VC_INDEX, pFly->_DEFAULT_AMOUNT + pFly->_BONUS_AMOUNT);

		// 월 구매 이벤트 확인
		NResource::Static::InstancePtr()->GetMonthChargingResource()->SendMonthChargeEventItem(this);
		this->GetUserInfo().reserve3 = time(NULL);

		// VIP Point 초기화
		this->GetBuff()->RefleshVIPBuff();

		// VIP Point
		NResource::VIPResource::Data & vipData = NResource::Static::Instance().GetVIPResource()->GetData();

		if (vipData._MAX_VP < static_cast<int>(this->GetUserInfo().reserve4) + pFly->_DEFAULT_AMOUNT + pFly->_BONUS_AMOUNT)
			this->GetUserInfo().reserve4 = vipData._MAX_VP;
		else
			this->GetUserInfo().reserve4 += pFly->_DEFAULT_AMOUNT + pFly->_BONUS_AMOUNT;

		TESTLOG("VIP point = %d", this->GetUserInfo().reserve4);

		this->GetBuff()->SetVIPBuff();

		this->FlushUserInfoCache();
	}

	// Kakao로 과금 정보 전송
	if (clsReceiptData._marketType == 0 || clsReceiptData._marketType == 1)
	{
		NProcess::KakaoSender::Param clsParam;
		clsParam._socialID	= this->GetSocialID().c_str();
		clsParam._company	= this->GetCompany();
		clsParam._nPrice	= pFly->_PRICE;
		clsParam._buySeq	= clsReceiptData._buySeq;

		NProcess::Static::InstancePtr()->GetKakaoSender().Push(clsParam);
	}

//	DecreaseRefCount();

	if (this->GetEnumState() == User::EnumState::RECEIPT_CHECKING_CLOSE)
	{
		this->OnDisconnect();
	}
	else
	{
		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pAck << static_cast<int16_t>(ACK_OK);
		*pAck << static_cast<uint32_t>(clsReceiptData._validatorStatus);
		*pAck << this->GetVirtualCurrency()->GetZen();
		pAck->MakePacket(CMD_SC_REG_BUY_ITEM_RESULT);
		this->Send(pAck);

		this->SetEnumState(User::EnumState::__NONE__);
		this->SetState(NState::Static::Instance().MAINFRIENDLIST());
	}
}

void
User::OnResponse(::Database::Command * pCommand)
{
	User::State * pState = this->GetState();
	if (NULL == pState)
		return;

	pState->OnResponse(pCommand);
	::Database::GETCOMMANDPOOL()->DEL(pCommand);
}

void
User::OnError(::Database::Command * pCommand, const char* err, int errCode)
{

}

void
User::SetState(State * state)
{
	_state = state;

	if (_clsStateHistory.size() > 10)
		_clsStateHistory.pop_front();

	_clsStateHistory.push_back(state);

	// 로그인 시 승점 데이터 검사
	if (_state == NState::Static::Instance().MAINFRIENDLIST())
	{
		_loginTime = time(NULL);
		time_t initTime = NLogic::NFunction::GetWeekInitTime();

		if (this->GetUserInfo().wp_reg_date < static_cast<uint64_t>(initTime))
		{
			this->GetUserInfo().wp_last_reg_date	= this->GetUserInfo().wp_reg_date;
			this->GetUserInfo().wp_last_week		= this->GetUserInfo().wp_cur_week;
			this->GetUserInfo().wp_cur_week			= 0;
			this->GetUserInfo().wp_reg_date			= initTime;
			this->GetUserInfo().score				= 0;
			this->GetUserInfo().heart_blocked		= 0;
		}

		// 2주 이상 경과한 경우 모든 데이터 초기화
		time_t initTime2 = initTime - (7 * 3600 * 24);

		if (this->GetUserInfo().wp_reg_date < static_cast<uint64_t>(initTime2))
		{
			this->GetUserInfo().wp_last_reg_date = 0;
			this->GetUserInfo().wp_last_week	= 0;
			this->GetUserInfo().wp_cur_week		= 0;
			this->GetUserInfo().wp_reg_date		= initTime2;
			this->GetUserInfo().score			= 0;
			this->GetUserInfo().heart_blocked	= 0;
		}

		// 승점 정보 Memcache에 반영
		_score->SetMemcache();

		// 자신이 거래소에 등록한 아이템을 로그인 시점에 한번 로딩한다.
		_trade->TradeItemLoadToDatabase();

		// 접속 이벤트 처리
		NResource::Static::InstancePtr()->GetConnectEventResource()->SendConnectEventReward(this);

		// PVP 전국 랭킹 점수 초기화
		if (true == NResource::Static::InstancePtr()->GetEventTime()->IsPVPWorldRankingEvent(this))
		{
//			NResource::EventTimeData::Key clsKey(NResource::EventTimeResource::EventType::EM_EVENT_TYPE_PVP_WORLD_RANKING, 0);
//			NResource::EventTimeData::Flyweight * pFly = NResource::Static::InstancePtr()->GetEventTime()->GetFly(this, clsKey);
			NResource::EventTimeData::Flyweight * pFly = NResource::Static::InstancePtr()->GetEventTime()->GetFly(this, static_cast<int>(NResource::EventTimeResource::EventType::EM_EVENT_TYPE_PVP_WORLD_RANKING));
			if (NULL != pFly)
			{
				if (this->GetUserInfo().reserve2 < static_cast<uint64_t>(pFly->_START_SEC))
				{
					this->GetUserInfo().reserve1 = 0;				// 점수 초기화
					this->GetUserInfo().reserve2 = time(NULL);		// 초기화 시간 기록
					this->FlushUserInfo();

					if (_userInfo.main_slot_index < -1 || _userInfo.main_slot_index > 7)
					{
						DEBUGLOG("ERROR %s mainslotIndex : %d GID : %d", __FUNCTION__,
							_userInfo.main_slot_index, this->GetUserSeq());

						_userInfo.main_slot_index = 0;
					}
				}
			}
		}



	}
}

void
User::PreFlush()
{
	//this->GetUserInfo().array_Slot[this->GetCharacterInfo().slotindex].level = this->GetCharacterInfo().level;

	// equip update
	if (true == this->IsCacheBagInfo())
		this->GetEquip()->UpdateCharacterInfo();
	this->save_DungeonClear_BagOrder_Buff_BattleAfterEffect();
	this->save_Daily_Mission_Info();
}

void
User::SetBattle_afterEffect()
{
	std::time_t t = std::time(0);  // t is an integer type
	unsigned int nTime = t;

	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
		this->GetUserInfo().battle_aftereffect_time = nTime + ( 20 );
	else
		this->GetUserInfo().battle_aftereffect_time = nTime + ( 60 * 2 );

	_battle_aftereffect = true;
}

void
User::CancelBattle_afterEffect()
{
	this->GetUserInfo().battle_aftereffect_time = 0;
	_battle_aftereffect = false;
}

bool
User::EndBattle_afterEffect()
{
	std::time_t t = std::time(0);  // t is an integer type
	unsigned int nTime = t;

	if (nTime < this->GetUserInfo().battle_aftereffect_time)
	{
		return false;
	}

	this->GetUserInfo().battle_aftereffect_time = 0;
	_battle_aftereffect = false;

	return true;
}

void
User::SetPVPBattleResult_afterEffect()
{
}

void
User::SetPKBattleResult_afterEffect()
{
	int rank = 0;//::ProjectZ::NLogic::NFunction::GetPKSessionRank(this->GetParty(), this->GetUserInfo().userseq);
	int ep_this_game = NResource::Static::InstancePtr()->GetPointResource()->PKEvolvePoint(this, rank);

	this->GetBattleAfterEffect()->GetData()._hasData = 1;
	this->GetBattleAfterEffect()->GetData()._battle_type = 1;
	this->GetBattleAfterEffect()->GetData()._winRank = rank;
	this->GetBattleAfterEffect()->GetData()._win_point = 0;
	this->GetBattleAfterEffect()->GetData()._evolve_point = ep_this_game;
}

void
User::UpdateLatency()
{
	_latency = ProjectZ::NLogic::NFunction::GetTickCount();
}

unsigned long
User::GetLastLatency()
{
	return _latency;
}

void
User::ChangeMainSlot()
{
	_clsDungeonClearInfo.Initialize(0);
	_clsDungeonClearPoint.Initialize(-1);
	_clsBagOrder.Initialize(0);

	this->GetBattleAfterEffect()->Finalize();

	_questInfo->Finalize();

	this->load_DungeonClear_BagOrder_Buff_BattleAfterEffect();
	this->load_Daily_Mission_Info();
	this->GetBuff()->SetVIPBuff();
}

void
User::load_DungeonClear_BagOrder_Buff_BattleAfterEffect()
{
	// dungeon_clear_info log
	TESTLOG("%s userseq : %d [%s]", __FUNCTION__, this->GetUserSeq(), this->GetCharacterInfo().dungeon_clear_info.c_str());

	if (this->GetCharacterInfo().dungeon_clear_info.empty())
	{
		_clsDungeonClearInfo.Initialize(0);
		_clsDungeonClearPoint.Initialize(-1);
	}
	else
	{
		// dungeon_clear_info
		std::vector<std::string> strVector;

		NLogic::NFunction::StringSplit(this->GetCharacterInfo().dungeon_clear_info, ',', strVector);

		std::vector<int> intVector;
		int index = 0;
		auto iter = strVector.begin();
		for (; iter != strVector.end(); ++iter)
		{
			NLogic::NFunction::StringToIntSplit((*iter), ':', intVector);

			if (false == _clsDungeonClearInfo.SetValue(index, intVector[0]))
			{
				DEBUGLOG("ERROR %s _clsDungeonClearInfo.SetValue Index : %d value : %d", __FUNCTION__, index, intVector[0]);
				break;
			}

			if (false == _clsDungeonClearPoint.SetValue(index, -1))
			{
				DEBUGLOG("ERROR %s _clsDungeonClearPoint.SetValue Index : %d value : %d", __FUNCTION__, index, -1);
				break;
			}

			if (2 <= intVector.size())
			{
				if (1 == intVector[0])
				{
					if (false == _clsDungeonClearPoint.SetValue(index, intVector[1]))
					{
						DEBUGLOG("ERROR %s _clsDungeonClearPoint.SetValue Index : %d value : %d", __FUNCTION__, index, intVector[1]);
						break;
					}
				}
			}
			index++;
			intVector.clear();
		}
	}

	// bag_order_info
	{
		std::vector<int> clsBagOrderVector;
		//NLogic::NFunction::StringToIntSplit(this->GetCharacterInfo().bag_order_info, ',', _array_bag_order_info);
		NLogic::NFunction::StringToIntSplit(this->GetCharacterInfo().bag_order_info, ',', clsBagOrderVector);

		int index = 0;
		auto itr = clsBagOrderVector.begin();
		for (;itr != clsBagOrderVector.end(); ++itr)
		{
			if (false == _clsBagOrder.SetValue(index, (* itr)))
			{
				DEBUGLOG("ERROR BAGORDER LOAD FAIL INDEX : %d VALUE : %d GID : %d", index, (* itr), this->GetUserSeq());
				break;
			}

			index++;
		}
	}



	{
		int index = 0;
		int DataIndex = 0;
		int valueIndex = 0;
		std::string strTemp;

		while (this->GetCharacterInfo().buff_info[index] != '\0')
		{
			if (',' == this->GetCharacterInfo().buff_info[index])
			{
				switch(valueIndex)
				{
				case 0:
					_buff->GetData(static_cast<NLogic::Buff::BuffType>(DataIndex))->u8type = atoll(strTemp.c_str());
					break;
				case 1:
					_buff->GetData(static_cast<NLogic::Buff::BuffType>(DataIndex))->u16skill_tid = atoll(strTemp.c_str());
					break;
				case 2:
					_buff->GetData(static_cast<NLogic::Buff::BuffType>(DataIndex))->u8skill_level = atoll(strTemp.c_str());
					break;
				case 3:
					_buff->GetData(static_cast<NLogic::Buff::BuffType>(DataIndex))->s16skill_value = atoll(strTemp.c_str());
					break;
				default:
					break;
				}

				strTemp.clear();
				valueIndex++;
				index++;
				continue;
			}
			else if ('|' == this->GetCharacterInfo().buff_info[index])
			{
				_buff->GetData(static_cast<NLogic::Buff::BuffType>(DataIndex))->_regdate = atoll(strTemp.c_str());
				strTemp.clear();
				valueIndex = 0;
				index++;
				DataIndex++;
			}
			else
			{
				strTemp += this->GetCharacterInfo().buff_info[index];
				index++;
			}
		}

		// 길드 OFF인 경우 길드 버프 클리어
		if (false == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(ContentsOpen::GUILD))
		{
			NLogic::Buff::Data * pGuildBuffData = _buff->GetData(NLogic::Buff::BuffType::GUILD);
			if (NULL != pGuildBuffData)
				pGuildBuffData->Clear();
		}
	}

	{
		int index = 0;
		int valueIndex = 0;
		std::string strTemp;

		while (this->GetCharacterInfo().battle_afterEffect_info[index] != '\0')
		{
			if (',' == this->GetCharacterInfo().battle_afterEffect_info[index])
			{
				switch(valueIndex)
				{
				case 0:
					this->GetBattleAfterEffect()->GetData()._hasData = atoll(strTemp.c_str());
					break;
				case 1:
					this->GetBattleAfterEffect()->GetData()._battle_type = atoll(strTemp.c_str());
					break;
				case 2:
					this->GetBattleAfterEffect()->GetData()._winRank = atoll(strTemp.c_str());
					break;
				case 3:
					this->GetBattleAfterEffect()->GetData()._win_point = atoll(strTemp.c_str());
					break;
				case 4:
					this->GetBattleAfterEffect()->GetData()._evolve_point = atoll(strTemp.c_str());
					break;
				default:
					break;
				}

				strTemp.clear();
				valueIndex++;
				index++;
				continue;
			}
			else if ('|' == this->GetCharacterInfo().battle_afterEffect_info[index])
			{
				break;
			}
			else
			{
				strTemp += this->GetCharacterInfo().battle_afterEffect_info[index];
				index++;
			}
		}
	}
}

void
User::save_DungeonClear_BagOrder_Buff_BattleAfterEffect()
{
	{
		std::stringstream stream;
		for (int i = 0; i < MAX_DUNGEON_COUNT; i++)
		{

			int retClearValue = 0;
			if (false == this->_clsDungeonClearInfo.GetValue(i, retClearValue))
			{
				DEBUGLOG("ERROR %s _clsDungeonClearInfo.GetValue index : %d GID : %d", __FUNCTION__, i, this->GetUserSeq());
			}

			int retPointValue = 0;
			if (false == this->_clsDungeonClearPoint.GetValue(i, retPointValue))
			{
				DEBUGLOG("ERROR %s _clsDungeonClearPoint.GetValue index : %d GID : %d", __FUNCTION__, i, this->GetUserSeq());
			}

			stream << retClearValue << ":" << retPointValue;

			if ( i < MAX_DUNGEON_COUNT - 1)
				stream << ",";
		}
		this->GetCharacterInfo().dungeon_clear_info = stream.str().c_str();
		//DEBUGLOG("TRACE %s dungeon_clear_info size : %d GID : %d", __FUNCTION__, stream.str().length(), this->GetUserSeq());
	}
	{
		std::stringstream stream;
		for (int i = 0; i < BAG_TYPE_MAX; i++)
		{
			int resultValue = 0;
			if (false == _clsBagOrder.GetValue(i, resultValue))
			{
				DEBUGLOG("ERROR BAGORDER SAVE FAIL INDEX : %d VALUE : %d GID : %d", i, resultValue, this->GetUserSeq());
				break;
			}

			stream << resultValue;

			if ( i < BAG_TYPE_MAX - 1)
				stream << ",";
		}
		this->GetCharacterInfo().bag_order_info = stream.str().c_str();
	}
	{
		std::stringstream stream;
		for (int i = static_cast<int>(NLogic::Buff::BuffType::WINPOINT); i <= static_cast<int>(NLogic::Buff::BuffType::GUILD); i++)
		{
			stream << _buff->GetDataVector()[i]->u8type;
			stream << ",";
			stream << _buff->GetDataVector()[i]->u16skill_tid;
			stream << ",";
			stream << _buff->GetDataVector()[i]->u8skill_level;
			stream << ",";
			stream << _buff->GetDataVector()[i]->s16skill_value;
			stream << ",";
			stream << _buff->GetDataVector()[i]->_regdate;
			stream << "|";
		}

		DEBUGLOG("PRE FLUSH BUFF : %s", stream.str().c_str());
		this->GetCharacterInfo().buff_info = stream.str().c_str();
	}

	{
		std::stringstream stream;
		stream << this->GetBattleAfterEffect()->GetData()._hasData;
		stream << ",";
		stream << this->GetBattleAfterEffect()->GetData()._battle_type;
		stream << ",";
		stream << this->GetBattleAfterEffect()->GetData()._winRank;
		stream << ",";
		stream << this->GetBattleAfterEffect()->GetData()._win_point;
		stream << ",";
		stream << this->GetBattleAfterEffect()->GetData()._evolve_point;
		stream << "|";

		DEBUGLOG("PRE BATTLEAFTEREFFECT BUFF : %s", stream.str().c_str());
		this->GetCharacterInfo().battle_afterEffect_info = stream.str().c_str();
	}
}

void
User::load_Daily_Mission_Info()
{
	/*
	 * 일일 미션 정보 Loading
	 * GetCharacterInfo().daily_mission_info
	 * 		0,0,0|1,0,0|2,0,0|3,0,0|4,0,0 ...
	 */

	if (0 >= this->GetCharacterInfo().daily_mission_info.length())
	{
		this->_dailyMission->Initialize();
		return;
	}

	std::vector<std::string> clsMainVector;
	NLogic::NFunction::StringSplit(this->GetCharacterInfo().daily_mission_info, '|', clsMainVector);

	if (8 != clsMainVector.size())
	{
		DEBUGLOG("%s : INVALID DATA=[%s] user_seq=%d, char_seq=%d", __FUNCTION__,
				this->GetCharacterInfo().daily_mission_info.c_str(), this->GetUserSeq(), this->GetCharacterInfo().characterseq);
		this->_dailyMission->Initialize();
		return;
	}

	int startIndex	= static_cast<int>(NLogic::DailyMission::MissionType::SPECIAL_MISSION);
	int endIndex	= static_cast<int>(NLogic::DailyMission::MissionType::__MAX__);

	for (; startIndex < endIndex; startIndex++)
	{
		std::vector<std::string> clsSubVector;
		NLogic::NFunction::StringSplit(clsMainVector[startIndex], ',', clsSubVector);

		NLogic::DailyMission::MissionType eType = static_cast<NLogic::DailyMission::MissionType>(startIndex);

		if (3 != clsSubVector.size())
		{
			DEBUGLOG("%s : INVALID DATA=[%s] user_seq=%d, char_seq=%d", __FUNCTION__,
					this->GetCharacterInfo().daily_mission_info.c_str(), this->GetUserSeq(), this->GetCharacterInfo().characterseq);
			this->_dailyMission->Initialize();
			return;
		}

		this->_dailyMission->GetData(eType)->missionType	= atoi(clsSubVector[0].c_str());
		this->_dailyMission->GetData(eType)->completeCount	= atoi(clsSubVector[1].c_str());
		this->_dailyMission->GetData(eType)->isReward		= atoi(clsSubVector[2].c_str());
	}
}

void
User::save_Daily_Mission_Info()
{
	std::stringstream stream;

	int startIndex	= static_cast<int>(NLogic::DailyMission::MissionType::SPECIAL_MISSION);
	int endIndex	= static_cast<int>(NLogic::DailyMission::MissionType::__MAX__);

	for (; startIndex < endIndex; startIndex++)
	{
		NLogic::DailyMission::MissionType eType = static_cast<NLogic::DailyMission::MissionType>(startIndex);

		stream << this->_dailyMission->GetData(eType)->missionType;
		stream << ",";
		stream << this->_dailyMission->GetData(eType)->completeCount;
		stream << ",";
		stream << this->_dailyMission->GetData(eType)->isReward;

		if (startIndex < endIndex - 1)
		{
			stream << "|";
		}
	}

	DEBUGLOG("PRE FLUSH DAILY_MISSION : %s", stream.str().c_str());
	this->GetCharacterInfo().daily_mission_info = stream.str().c_str();
}

void
User::IncreaseRefCount()
{
	_refCount += 1;

	if (0 < _userSeq)
		DEBUGLOG("REF IncreaseRefCount : userseq=%d, refcount=%d pointer : %x", _userSeq, _refCount, this);
}

void
User::DecreaseRefCount()
{

	if (true == Factory::Instance().DEL(this))
	{
		this->FlushUserInfo();
		this->FlushCharacterInfo();
		this->UnRegistLocation();

		::ProjectZ::NProxy::Final(this);
	}
}

void
User::DecreaseRefCount_PhysicalChange()
{
	if (true == Factory::Instance().DEL(this))
	{
		this->FlushUserInfo();
		this->FlushCharacterInfo();
		this->UnRegistLocation();
	}
}

unsigned int
User::GetRefCount()
{
	return _refCount;
}

void
User::SetEnumState(User::EnumState state)
{
	_enumStateType = state;

	if (_clsEnumStateHistory.size() > 10)
		_clsEnumStateHistory.pop_front();

	_clsEnumStateHistory.push_back(state);
}

void
User::RewindState()
{
	int order = 0;
	auto itr = _clsStateHistory.rbegin();
	for (;itr != _clsStateHistory.rend(); ++itr)
	{
		State * pState = (* itr);
		if (NULL != pState)
		{
			::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "STATE HISTORY ORDER : %d STATE : %s GID : %d", order, pState->GetName().c_str(), this->GetUserSeq());
		}
		order++;
	}
}

void
User::RewindEnumState()
{
	int order = 0;
	auto itr = _clsEnumStateHistory.rbegin();
	for (;itr != _clsEnumStateHistory.rend(); ++itr)
	{
		User::EnumState enumState = (* itr);
		::Logger::GETLOG()->ToAll(::Logger::OBSERVER, "ENUMSTATE HISTORY ORDER : %d ENUMSTATE : %d GID : %d", order, enumState, this->GetUserSeq());
		order++;
	}
}

void
User::CheckChief()
{
	if (NULL == this->GetSpace()) return;
	if (false == this->GetSpace()->IsDungeon()) return;

	NLogic::Party * pParty = this->GetParty();
	if (NULL == pParty) return;

	User * pChief = pParty->GetMaster();
	if (NULL == pChief) return;

	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	pNoti->MsgCat("%d", pChief->GetUserSeq());
	pNoti->MakePacket(CMD_SN_DUNGEON_DELEGATE_CHIEF);
	this->Send(pNoti);
}

} /* namespace ProjectZ */



